package com.haiyou.data.common.accessor.redis.redisson;

import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

import org.apache.commons.lang3.Validate;
import org.redisson.api.RAtomicLong;
import org.redisson.api.RedissonClient;

import com.alibaba.fastjson2.util.TypeUtils;
import com.google.common.collect.Maps;
import com.haiyou.common.entity.Entity;
import com.haiyou.common.entity.KeyPrefixChecker;
import com.haiyou.common.entity.Prefix;
import com.haiyou.common.id.IdCreator;
import com.haiyou.common.spring.util.SpringUtil;
import com.haiyou.common.system.Properties;
import com.haiyou.common.util.random.ProbabilityUtils;
import com.haiyou.common.util.reflect.AnnotationFinder;
import com.haiyou.common.util.string.StringUtils;
//import com.haiyou.data.center.keyGenerator.KeyGeneratorService;
import com.haiyou.data.common.accessor.AbstractAccessor;
import com.haiyou.data.common.accessor.annotation.ExpiryPolicy;
import com.haiyou.data.common.cache.redis.RKeys;
import com.haiyou.data.common.cache.redis.redisson.RedisRedisson;
import com.haiyou.data.common.cache.redis.redisson.annotation.RDatabase;

import lombok.Getter;

public abstract class RedissonAccessor<K extends Serializable & Comparable<K>, V extends Entity<K>>
		extends AbstractAccessor<K, V> {

	public static Map<String, RedissonAccessor<?, ?>> pool = Maps.newHashMap();

	public static <A extends RedissonAccessor<?, ?>> A getInstance(String keyPrefix) {
		A instance = (A) pool.get(keyPrefix);
		Validate.isTrue(instance != null, "%s 的存储器不存在", keyPrefix);
		return instance;
	}

	@Getter
	protected String redisAliasName;

	@Getter
	protected RedissonClient redissonClient;

	@Getter
	protected String keyPrefix;// 当前类型在redis上de专属前缀

	protected int timeToLive = -1;

	protected TimeUnit timeToLiveUnit = TimeUnit.MINUTES;

	@Override
	public void init() {
		super.init();
		RDatabase database = AnnotationFinder.findAnnotation(valueClass, RDatabase.class);
		Validate.isTrue(database != null, "[%s]没有配置redis数据库", valueClass);
		Validate.isTrue(!StringUtils.isEmpty(database.alias()));
		redisAliasName = database.alias();
		redissonClient = RedisRedisson.getRedissonClient(redisAliasName);

		Prefix prefix = AnnotationFinder.findAnnotation(getInitClass(), Prefix.class);
		KeyPrefixChecker.checkFlag(prefix.value());
		keyPrefix = prefix.value();

		ExpiryPolicy expiryPolicy = AnnotationFinder.findAnnotation(getInitClass(), ExpiryPolicy.class);
		if (expiryPolicy != null) {
			timeToLive = ProbabilityUtils.xTo2x(expiryPolicy.timeToLive());
			timeToLiveUnit = expiryPolicy.timeUnit();
		}

		RedissonAccessor<K, V> old = (RedissonAccessor<K, V>) pool.putIfAbsent(keyPrefix, this);
		Validate.isTrue(old == null, "重复注册[%s]数据存储器[%s],old=%s", keyPrefix, this, old);

	}

	@Override
	public void destory() {
		super.destory();
		persistKeyValue(keyPrefix, idAutoCreator().get());
	}

	/**
	 * 自动生成ID的数字起始值
	 * 
	 * @return
	 */
	protected long beginNumberId() {
		return 0L;
	}

	@Override
	public V generate(Consumer<V> consumer) {
		K k = null;
		V v = null;
		try {
			k = generateKey();
			v = valueClass.newInstance();
			v.setId(k);
			if (consumer != null)
				consumer.accept(v);
			put(k, v);
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage(), e);
		}
		return v;
	}

	@Override
	public K generateKey() {
		K id = super.generateKey();
		if (id != null)
			return id;
		long incred = idAutoCreator().incrementAndGet();
		if (keyClass.getName().compareTo(String.class.getName()) == 0)
			return id = (K) RKeys.createRId(keyPrefix, incred);
		return id = TypeUtils.cast(incred, keyClass);
	}

	/**
	 * 默认id自增工具
	 * 
	 * @return
	 */
	public RAtomicLong idAutoCreator() {
		RAtomicLong atomicLong = redissonClient
				.getAtomicLong(RKeys.createRKey(RAtomicLong.class, keyPrefix, "keyGenerator"));
		if (atomicLong.get() == 0L) {
			long begin = getKeyPersist(keyPrefix, beginNumberId());
			atomicLong.compareAndSet(0L, begin == 0L ? IdCreator.create() : begin);
		}
		return atomicLong;
	}

	/**
	 * 获取持久化 key 对应的值
	 * @param key
	 * @param defaultValue 默认值
	 * @return
	 */
	protected long getKeyPersist(String key, long defaultValue) {
		return defaultValue;
		//return SpringUtil.getBean(KeyGeneratorService.class).getKeyValueFromDb(key, defaultValue);
	}

	/**
	 * 持久化 key 对应的 value
	 * @param key
	 * @param value
	 */
	protected void persistKeyValue(String key, long value) {
		//SpringUtil.getBean(KeyGeneratorService.class).updateKeyValue2Db(redissonClient, key, value);
	}

	protected int lockWaitTime() {
		return Properties.lock_wait_time(keyPrefix);
	}

	protected int lockLeaseTime() {
		return Properties.lock_lease_time(keyPrefix);
	}

	protected TimeUnit lockTimeUnit() {
		return TimeUnit.valueOf(Properties.lock_time_unit(keyPrefix));
	}

}
